package com.xrf;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.core.app.ActivityCompat;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;
import android.widget.ZoomControls;
import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.data.ServiceFeatureTable;
import com.esri.arcgisruntime.geometry.AreaUnit;
import com.esri.arcgisruntime.geometry.AreaUnitId;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.GeodeticCurveType;
import com.esri.arcgisruntime.geometry.Geometry;
import com.esri.arcgisruntime.geometry.GeometryEngine;
import com.esri.arcgisruntime.geometry.GeometryType;
import com.esri.arcgisruntime.geometry.LinearUnit;
import com.esri.arcgisruntime.geometry.LinearUnitId;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.Polygon;
import com.esri.arcgisruntime.geometry.Polyline;
import com.esri.arcgisruntime.geometry.SpatialReference;
import com.esri.arcgisruntime.layers.ArcGISTiledLayer;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.Viewpoint;
import com.esri.arcgisruntime.mapping.view.Callout;
import com.esri.arcgisruntime.mapping.view.DefaultMapViewOnTouchListener;
import com.esri.arcgisruntime.mapping.view.Graphic;
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
import com.esri.arcgisruntime.mapping.view.IdentifyGraphicsOverlayResult;
import com.esri.arcgisruntime.mapping.view.LocationDisplay;
import com.esri.arcgisruntime.mapping.view.MapScaleChangedEvent;
import com.esri.arcgisruntime.mapping.view.MapScaleChangedListener;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.mapping.view.SketchCreationMode;
import com.esri.arcgisruntime.mapping.view.SketchEditor;
import com.esri.arcgisruntime.mapping.view.SketchGeometryChangedEvent;
import com.esri.arcgisruntime.mapping.view.SketchGeometryChangedListener;
import com.esri.arcgisruntime.mapping.view.SketchStyle;
import com.esri.arcgisruntime.mapping.view.ViewpointChangedEvent;
import com.esri.arcgisruntime.mapping.view.ViewpointChangedListener;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
import com.esri.arcgisruntime.symbology.TextSymbol;
import com.example.mobilemap.Utility.BaseUtility;
import com.example.mobilemap.Utility.ConstValue;
import com.example.mobilemap.Utility.CoordinateTransTools;
import com.example.mobilemap.Utility.GlobalValues;
import com.example.mobilemap.Utility.LocationServiceUtility;
import com.example.mobilemap.Utility.MapUtil;
import com.example.mobilemap.Widget.Scalebar;
import com.example.mobilemap.dialog.BaseMapSelDlg;
import com.example.mobilemap.dialog.GeometryFileDlg;
import com.example.mobilemap.dialog.LayerCtrlDlg;
import com.example.mobilemap.dialog.ListView.ItemGeoFileAdapter;
import com.example.mobilemap.dialog.ListView.ItemGeoFileName;
import com.example.mobilemap.dialog.PtInputMainDlg;
import com.example.mobilemap.dialog.RedBlockInfoDlg;
import com.example.mobilemap.dialog.RedLineTreeDlg;
import com.example.mobilemap.dialog.TreeWidget.TreeNode;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnItemClick;

import static com.example.mobilemap.Utility.ConstValue.reqPermissions;

public class MainActivity extends AppCompatActivity {
    
    @BindView(R.id.mapView)
    MapView mMapView;
    @BindView(R.id.main_zoomctrl)
    ZoomControls zoomCtrl;
    @BindView(R.id.scale_bar)
    Scalebar scalebar;
    @BindView(R.id.long_lat_text_view)
    TextView longLatText;
    @BindView(R.id.compass)
    ImageView compass;
    @BindView(R.id.long_lat_show)
    LinearLayout compassAndLatLongLayout;
    @BindView(R.id.main_draw_layout)
    CardView drawLayout;
    @BindView(R.id.main_measure_layout)
    CardView measureLayout;
    @BindView(R.id.main_location_imageview)
    ImageView imgLocationBtn;
    @BindView(R.id.ImgeView_Erease)
    ImageView imgEreaseBtn;
    @BindView(R.id.main_searchbar_layout)
    CardView searchBarLayout;
    @BindView(R.id.search_view_ctrl)
    SearchView searchViewCtrl;
    @BindView(R.id.list_search_results)
    ListView listSearchResults;
    @BindView(R.id.cardview_search_results)
    CardView cardViewSearchRes;
    
    private LocationDisplay mLocationDisplay;
    private int oldScale = 1000000;
    private Handler handler = new Handler();
    private ConstValue.LocationType locType;
    private SketchEditor sketchEditor = null;
    private SketchEditor sketchEditorMeasure = null;
    private Graphic drawGraphic;
    private boolean isLocationOpened = false;
    private RedLineTreeDlg redLineTreeDlg = null;
    private Graphic textGC = null;
    private View contentViewGroup;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        try {
            Log.d(ConstValue.LogMyTag, "onCreate");
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            setHalfTransparent();
            setFitSystemWindow(false);
            ButterKnife.bind(this);
            setMapView();
            initSysValue();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    zoomToGlobal(true);
                }
            }, 1200);
        } catch (Exception e) {
            String str = e.toString();
            Log.e(ConstValue.LogMyTag, e.toString());
        }
    }
    
    private void setMapView() {
        try {
            ArcGISRuntimeEnvironment.setLicense(getResources().getString(R.string.arcgis_license_key));
            mMapView.setBackgroundColor(Color.WHITE);
            
            ArcGISTiledLayer layer = new ArcGISTiledLayer(getResources().getString(R.string.URL_Service_js_yxdt_));
            layer.setName(getResources().getString(R.string.LayerName_JS_Image));
            ArcGISTiledLayer diglayer = new ArcGISTiledLayer(getResources().getString(R.string.URL_Service_js_sldt_));
            diglayer.setName(getResources().getString(R.string.LayerName_JS_Vector));
            
            GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
            GraphicsOverlay thematicOverlay = new GraphicsOverlay();
            
            Basemap basemap = new Basemap(layer);
            ArcGISMap map = new ArcGISMap(basemap);
            basemap.getBaseLayers().add(diglayer);
            
            map.setMinScale(1200000);
            map.setMaxScale(5000);
            mMapView.setAttributionTextVisible(false);
            mMapView.getBackgroundGrid().setColor(Color.WHITE);
            mMapView.setMap(map);
            mMapView.getGraphicsOverlays().add(graphicsOverlay);
            mMapView.getGraphicsOverlays().add(thematicOverlay);
            diglayer.setVisible(false);
            
            MapUtil.getInstance().setMainReference(layer.getSpatialReference());
            MapUtil.getInstance().setMainMap(mMapView);
            MapUtil.getInstance().setGraphicsOverlay(graphicsOverlay);
            MapUtil.getInstance().setThematicOverlay(thematicOverlay);
            
            mLocationDisplay = mMapView.getLocationDisplay();
            mLocationDisplay.setShowLocation(true);
            mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.RECENTER);
            mLocationDisplay.startAsync();
            
            zoomCtrl.setOnZoomInClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mMapView.setViewpointScaleAsync(mMapView.getMapScale() * 0.5);
                }
            });
            
            zoomCtrl.setOnZoomOutClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mMapView.setViewpointScaleAsync(mMapView.getMapScale() * 2.0);
                }
            });
            
            mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(MainActivity.this, mMapView) {
                @Override
                public boolean onSingleTapUp(MotionEvent e) {
                    android.graphics.Point pt = new android.graphics.Point(
                            Math.round(e.getX()),
                            Math.round(e.getY()));
                    if (pt == null || thematicOverlay.getGraphics().size() < 1) {
                        return super.onSingleTapUp(e);
                    }
                    
                    MapUtil.getInstance().getSelectGraphics();
                    final ListenableFuture<IdentifyGraphicsOverlayResult> identifyGraphic =
                            mMapView.identifyGraphicsOverlayAsync(thematicOverlay,
                                    pt, 10.0, false, 2);
                    
                    identifyGraphic.addDoneListener(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                IdentifyGraphicsOverlayResult grOverlayResult = identifyGraphic.get();
                                // get the list of graphics returned by identify graphic overlay
                                List<Graphic> graphic = grOverlayResult.getGraphics();
                                if (!graphic.isEmpty()) {
                                    for (Graphic gc : graphic) {
                                        if (gc.getGeometry().getGeometryType() != GeometryType.POLYGON) {
                                            continue;
                                        }
                                        Point pit = mMapView.screenToLocation(pt);
                                        if (GeometryEngine.within(
                                                new Point(pit.getX(), pit.getY(), pit.getZ(),
                                                        gc.getGeometry().getSpatialReference()),
                                                gc.getGeometry())) {
                                            mMapView.getCallout().dismiss();
                                            showCallOut(gc, pit);
                                        }
                                    }
                                }
                            } catch (Exception e) {
                                String str = e.toString();
                                GlobalValues.getInstance().messageToast(e.toString());
                            }
                        }
                    });
                    return super.onSingleTapUp(e);
                }
            });
            
            zoomCtrl.setVisibility(View.GONE);
            initRedLineData();
        } catch (Exception e) {
            GlobalValues.getInstance().messageToast("Some errors occurred in MainActivity_setMapView : " + e.toString());
        }
    }
    
    private void initRedLineData() {
        try {
            ServiceFeatureTable redLineCountry =
                    new ServiceFeatureTable("http:localhost:6080/arcgis/rest/services/tz/redline1213/MapServer/0");
            ServiceFeatureTable redLineProvince =
                    new ServiceFeatureTable("http:localhost:6080/arcgis/rest/services/tz/redline1213/MapServer/1");
            
            QueryParameters parameters = new QueryParameters();
            parameters.setWhereClause("FID>=0");
            final ListenableFuture<FeatureQueryResult> result =
                    redLineCountry.queryFeaturesAsync(parameters, ServiceFeatureTable.QueryFeatureFields.LOAD_ALL);
            
            result.addDoneListener(() -> {
                try {
                    FeatureQueryResult re = result.get();
                    MapUtil.getInstance().createRedGraphicByQueryResult(re, redLineCountry.getTableName());
                    
                    QueryParameters parameters2 = new QueryParameters();
                    parameters2.setWhereClause("FID>=0");
                    final ListenableFuture<FeatureQueryResult> result2 =
                            redLineProvince.queryFeaturesAsync(parameters2, ServiceFeatureTable.QueryFeatureFields.LOAD_ALL);
                    
                    result2.addDoneListener(() -> {
                        try {
                            FeatureQueryResult re2 = result2.get();
                            MapUtil.getInstance().createRedGraphicByQueryResult(re2, redLineProvince.getTableName());
                            MapUtil.getInstance().setIsLayerLoaded(true);
                            
                            if (redLineTreeDlg == null) {
                                redLineTreeDlg = new RedLineTreeDlg(MainActivity.this);
                                Log.d(ConstValue.LogMyTag, "RedLineTreeDlg is initialed");
                            }
                        } catch (Exception e) {
                            Log.e("admin", e.toString());
                        }
                    });
                } catch (Exception e) {
                    StackTraceElement ste = e.getStackTrace()[0];
                    Log.e("admin", e.toString());
                }
            });
        } catch (Exception e) {
            GlobalValues.getInstance().messageToast("Some errors occurred in MainActivity_initRedLineData : " + e.toString());
        }
    }
    
    private void initSysValue() {
        try {
            // App initialization
            GlobalValues.getInstance().setAppFilePath(this.getFilesDir().getPath());
            GlobalValues.getInstance().setMainActivityContext(MainActivity.this);
            
            if (!LocationServiceUtility.isOpenLocService(MainActivity.this)) {
                LocationServiceUtility.gotoLocServiceSettings(MainActivity.this);
            }
            
            if (!LocationServiceUtility.checkAppPermission(MainActivity.this)) {
                ActivityCompat.requestPermissions(
                        MainActivity.this,
                        reqPermissions,
                        1);
                for (String str : reqPermissions) {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(
                            MainActivity.this,
                            str)) {
                        GlobalValues.getInstance().messageToast("Location permission required.");
                    }
                }
            }
            
            searchViewCtrl.setQuery("", false);
            searchViewCtrl.setIconified(true);
            searchViewCtrl.setIconifiedByDefault(false);
            
            searchViewCtrl.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String s) {
                    return false;
                }
                
                @Override
                public boolean onQueryTextChange(String s) {
                    if (!MapUtil.getInstance().getIsLayerLoaded()) {
                        GlobalValues.getInstance().messageToast("Layer not loaded, please wait.");
                        return false;
                    }
                    
                    if (s.length() < 1) {
                        return false;
                    }
                    
                    List<TreeNode> reList = MapUtil.getInstance().fuzzyQueryRedLineName(s);
                    List<ItemGeoFileName> list_items = new ArrayList<ItemGeoFileName>();
                    if (reList.size() < 1) {
                        return false;
                    }
                    
                    for (TreeNode node : reList) {
                        list_items.add(new ItemGeoFileName(node.getName()));
                    }
                    
                    if (list_items.size() > 0) {
                        ItemGeoFileAdapter adapter = new ItemGeoFileAdapter(
                                MainActivity.this, R.layout.list_item, list_items);
                        listSearchResults.setAdapter(adapter);
                        cardViewSearchRes.setVisibility(View.VISIBLE);
                        cardViewSearchRes.bringToFront();
                    }
                    
                    return true;
                }
            });
            
            searchViewCtrl.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View view, boolean b) {
                    if (b && searchViewCtrl.getQuery().length() > 0) {
                        cardViewSearchRes.setVisibility(View.VISIBLE);
                    } else {
                        cardViewSearchRes.setVisibility(View.GONE);
                    }
                }
            });
        } catch (Exception ce) {
            GlobalValues.getInstance().messageToast(ce.toString());
        }
    }
    
    @OnClick(R.id.main_global_btn)
    void zoomToGlobal() {
        zoomToGlobal(false);
    }
    
    private void zoomToGlobal(boolean isFirst) {
        ArcGISMap map = mMapView.getMap();
        if (map != null) {
            Basemap basemap = map.getBasemap();
            Envelope gEnv = new Envelope(119.64, 31.958756,
                    120.491667, 33.207781, mMapView.getSpatialReference());
            MapUtil.getInstance().setGlobalExtent(gEnv);
            ListenableFuture future = mMapView.setViewpointAsync(new Viewpoint(gEnv));
            
            if (isFirst) {
                future.addDoneListener(new Runnable() {
                    @Override
                    public void run() {
                        setMapViewListener();
                        setCoord(mMapView.getVisibleArea().getExtent().getCenter());
                        setScalebar((int) mMapView.getMapScale(), false);
                    }
                });
            } else {
                mMapView.setViewpointRotationAsync(0);
            }
        }
    }
    
    private void setCoord(Point centerPnt) {
        try {
            CoordinateTransTools.Point tranPoint = CoordinateTransTools.transform(new CoordinateTransTools.Point(centerPnt.getX(), centerPnt.getY()));
            String resultStr = "Coordinates: (";
            resultStr += BaseUtility.formatCoord(tranPoint.getLon());
            resultStr += "E, ";
            resultStr += BaseUtility.formatCoord(tranPoint.getLat());
            resultStr += "N)  ";
            resultStr += GlobalValues.getInstance().degree2DfmStr(tranPoint.getLon());
            resultStr += "E, ";
            resultStr += GlobalValues.getInstance().degree2DfmStr(tranPoint.getLat());
            resultStr += "N";
            longLatText.setText(resultStr);
        } catch (Exception e) {
            GlobalValues.getInstance().messageToast("Some errors occurred in MainActivity_setCoord : " + e.toString());
        }
    }
    
    private int setScalebar(int scale, boolean direction) {
        return scalebar.updateScale(scale, direction);
    }
    
    private void setMapViewListener() {
        try {
            longLatText.setVisibility(View.VISIBLE);
            compass.setVisibility(View.VISIBLE);
            compass.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mMapView.setViewpointRotationAsync(0);
                }
            });
            
            mMapView.addViewpointChangedListener(new ViewpointChangedListener() {
                @Override
                public void viewpointChanged(ViewpointChangedEvent viewpointChangedEvent) {
                    Polygon polygon = mMapView.getVisibleArea();
                    setCoord(polygon.getExtent().getCenter());
                    compass.setRotation(-(float) mMapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE).getRotation());
                }
            });
            
            scalebar.setVisibility(View.VISIBLE);
            mMapView.addMapScaleChangedListener(new MapScaleChangedListener() {
                @Override
                public void mapScaleChanged(MapScaleChangedEvent mapScaleChangedEvent) {
                    int scale = (int) mMapView.getMapScale();
                    if (oldScale > scale) {
                        oldScale = setScalebar(scale, false);
                    } else {
                        oldScale = setScalebar(scale, true);
                    }
                }
            });
        } catch (Exception e) {
            GlobalValues.getInstance().messageToast("Some errors occurred in MainActivity_setMapViewListener : " + e.toString());
        }
    }
    
    // 其他方法由于篇幅限制，这里只展示部分核心代码...
    
    @Override
    protected void onPause() {
        mMapView.pause();
        super.onPause();
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        mMapView.resume();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMapView.dispose();
    }
    
    protected void setHalfTransparent() {
        try {
            if (Build.VERSION.SDK_INT >= 21) {
                View decorView = getWindow().getDecorView();
                int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
                decorView.setSystemUiVisibility(option);
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            } else if (Build.VERSION.SDK_INT >= 19) {
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            }
        } catch (Exception e) {
            GlobalValues.getInstance().messageToast("Some errors occurred in MainActivity_setHalfTransparent : " + e.toString());
        }
    }
    
    protected void setFitSystemWindow(boolean fitSystemWindow) {
        try {
            if (contentViewGroup == null) {
                contentViewGroup = ((ViewGroup) findViewById(android.R.id.content)).getChildAt(0);
            }
            contentViewGroup.setFitsSystemWindows(fitSystemWindow);
        } catch (Exception e) {
            GlobalValues.getInstance().messageToast("Some errors occurred in MainActivity_setFitSystemWindow : " + e.toString());
        }
    }
}